//=============================================================================
// Tripmine weapon Superclass
//=============================================================================
class ChaosWeapon extends TFWeapon abstract;

var() int Count;            				// use this to keep track of the current selected ammo and replicate this to clients
var() bool bChangedAmmo;   				// use this flag to break out of loop in change ammo functions and replicate this to clients
var() Int OldCount;         				// used to tell us when to play the "changeammo" function and do not replicate this to clients
var() bool bPlayChangeAmmo;			// used by the Animnotify to tell use when to change mesh/skins and do not replicate this to clients
var class<Weapon> MyParentClass;			// used to give parent class instead of alt. ammo class (i.e. CGL instead of CGLNapalm).
var() int SoundCount;
var bool bDroppingWeapon;
var float BotLastSpecialAmmoCheck;   // Use by the bot AI to check to see if it should use spcial ammo

struct AmmoTypeStruct
{
	var class<Ammunition> AmmoClass;
	var class<WeaponAttachment> Attachment;
	var class<Pickup> Pickup;
	var bool bSuperAmmoLimit;			//This ammo should not be given 999 ammo for things like mutant
} ; var array<AmmoTypeStruct> AmmoType;

var name AmmoSwitchAnim; 				//The animation used when switching out ammo

//-------------------------------------------------------------------------------------------------
// replication
//-------------------------------------------------------------------------------------------------
replication
{
	// Things the server should send to the client.
	reliable if( Role==ROLE_Authority )
		Count, SoundCount, bChangedAmmo, ClientDoAutoSwitch;

	// functions called by client on server
    	reliable if( bNetOwner && Role < ROLE_Authority )
        		ChaosWeaponOption;
    	reliable if( Role < ROLE_Authority )
        		ChangeAmmo;
}


//-------------------------------------------------------------------------------------------------
// ChangeAmmo
//   Switches ammo types.
//-------------------------------------------------------------------------------------------------
simulated exec function ChangeAmmo()
{
	local Inventory Inv;

   	if (!HasAmmo() || !HasOtherAmmo() )
		return;

   	while (!bChangedAmmo)
    {
		Count += 1;
		if (Count >= AmmoType.length)
			Count = 0;
		Inv = Pawn(Owner).FindInventoryType(AmmoType[Count].AmmoClass);
		if (Inv  != none  && Ammunition(inv).HasAmmo()) {
			bChangedAmmo=true;
			break;
		}
	}
   	bChangedAmmo=false; // Set to false, as we have changed ammo at this point and need to reset the flag
}


//-------------------------------------------------------------------------------------------------
// ChaosWeaponOption
//	This will activate or de-activate any special mode the weapon has availible to it.
// 	Implemented in subclasses.
//-------------------------------------------------------------------------------------------------
exec function ChaosWeaponOption();


//-------------------------------------------------------------------------------------------------
// Tick
//	Starts the ammo change process when the count has changed.
//-------------------------------------------------------------------------------------------------
simulated function Tick(float deltatime)
{
	Super.Tick(deltatime);


    if (Instigator != None && Instigator.Weapon != Self && !bDroppingWeapon && Ammo[0] != None && Ammo[0].AmmoAmount == 0 && HasOtherAmmo())
		ChangeAmmo();

	//Lets clients know ammo class so it can display the right ammo.
	AmmoClass[0] = AmmoType[Count].AmmoClass;
	if (OldCount != Count)
    {
		OldCount = Count;
		SwitchFireMode(Count);
		bPlayChangeAmmo=True;
		PlayChangeAmmo();
   	}
}


//-------------------------------------------------------------------------------------------------
// Timmer
//-------------------------------------------------------------------------------------------------
simulated function Timer()
{
	Super.Timer();
	bPlayChangeAmmo=False;
}


//-------------------------------------------------------------------------------------------------
// PutDown
//	This is needed to help prevent ANs for multi-ammo weapons.
//-------------------------------------------------------------------------------------------------
simulated function bool PutDown()
{
	local int Mode;

	if (ClientState == WS_BringUp || ClientState == WS_ReadyToFire) {
		// For our multi-ammo weapons Instigator.PendingWeapon maybe none so check for that
		if (Instigator != None && Instigator.PendingWeapon != None && !Instigator.PendingWeapon.bForceSwitch) {
			for (Mode = 0; Mode < NUM_FIRE_MODES; Mode++) {
				if (FireMode[Mode].bFireOnRelease && FireMode[Mode].bIsFiring)
				return false;
			}
		}
		if (Instigator != None && Instigator.IsLocallyControlled()) {
		for (Mode = 0; Mode < NUM_FIRE_MODES; Mode++) {
			if (FireMode[Mode].bIsFiring)
			ClientStopFire(Mode);
		}

		if (ClientState != WS_BringUp && HasAnim(PutDownAnim))
			PlayAnim(PutDownAnim, PutDownAnimRate, 0.0);
		}
		ClientState = WS_PutDown;

		SetTimer(0.3, false);
	}
	for (Mode = 0; Mode < NUM_FIRE_MODES; Mode++) {
		FireMode[Mode].bServerDelayStartFire = false;
		FireMode[Mode].bServerDelayStopFire = false;
	}
	if (Instigator != None)
		Instigator.AmbientSound = None;
	OldWeapon = None;
	return true; // return false if preventing weapon switch
}


//-------------------------------------------------------------------------------------------------
// HasAmmo. Check all ammo types, not just for the current fire mode.
//-------------------------------------------------------------------------------------------------
simulated function bool HasAmmo()
{
	local byte i;
	local Inventory Inv;

	for (i = 0; i < AmmoType.length; i++)
    {
		Inv = Pawn(Owner).FindInventoryType(AmmoType[i].AmmoClass);
       		if (Inv != none  && Ammunition(Inv).HasAmmo())
         			return true;
	}
    return false;
}


//-------------------------------------------------------------------------------------------------
// HasOtherAmmo. Does this weapon have alternate ammunition available?
// Useful to check this before switching ammo types needlessly.
//-------------------------------------------------------------------------------------------------
simulated function bool HasOtherAmmo()
{
	local Inventory Inv;
	local int i;

	if (Pawn(Owner) == none)
		return false;

	for (i = 0; i < AmmoType.Length; i++) {
		if (i != Count) {
			inv = Pawn(Owner).FindInventoryType(AmmoType[i].AmmoClass);
			if (inv != none  && Ammunition(inv).HasAmmo())
            				return true;
		}
	}
	return false;
}


//-------------------------------------------------------------------------------------------------
// OutOfAmmo
// Needed to add this for a weapon with multiple ammo types.
//-------------------------------------------------------------------------------------------------
simulated function OutOfAmmo()
{
    	if (Level.NetMode == NM_Standalone && !Instigator.IsLocallyControlled())
      		return;

	if (HasAmmo())
		ChangeAmmo();
   	else
   		ClientDoAutoSwitch();
}


//-------------------------------------------------------------------------------------------------
// ClientDoAutoSwitch
//-------------------------------------------------------------------------------------------------
simulated function ClientDoAutoSwitch()
{
	DoAutoSwitch();
}


//-------------------------------------------------------------------------------------------------
// PlayChangeAmmo.
//-------------------------------------------------------------------------------------------------
simulated function PlayChangeAmmo();


//-------------------------------------------------------------------------------------------------
// DropFrom
//-------------------------------------------------------------------------------------------------
function DropFrom(vector StartLocation)
{
    local int m;
	local Pickup Pickup;
    local Ammunition A;

    bDroppingWeapon=true;

    if (!bCanThrow || !HasAmmo())
        return;

    ClientWeaponThrown();

    for (m = 0; m < NUM_FIRE_MODES; m++)
    {
        if (FireMode[m].bIsFiring)
            StopFire(m);
    }

	if ( Instigator != None )
	{
		DetachFromPawn(Instigator);
	}

	Pickup = Spawn(PickupClass,,, StartLocation);
	if ( Pickup != None )
	{
    	Pickup.InitDroppedPickupFor(self);
	    Pickup.Velocity = Velocity;
        if (Instigator.Health > 0)
            WeaponPickup(Pickup).bThrown = true;
    }
    // Make sure Instigator has no more of that ammo left...
    A = Ammunition(Instigator.FindInventoryType(AmmoType[Count].AmmoClass));
    If( A != None)
    {
      //  Log("for some reason pawn sitll has this much ammo = " @A.AmmoAmount);
        A.AmmoAmount = 0;
    }
    Destroy();
}


//-------------------------------------------------------------------------------------------------
// GiveTo
//	Gives this weapon to a player. Also adds extra ammo types.
//-------------------------------------------------------------------------------------------------
function GiveTo(Pawn Other, optional Pickup Pickup)
{
	local int m;
	local ChaosWeapon W;
	local bool bPossiblySwitch, bJustSpawned;
	local byte MyCount;
	local Ammunition A;
	local WeaponPickup WP;

	Instigator = Other;

    W = ChaosWeapon(Instigator.FindInventoryType(class));
	if ( W == None )
    {
  		bJustSpawned = true;
		Super(Inventory).GiveTo(Other);
		bPossiblySwitch = true;
		W = self;
	}
	else if ( !W.HasAmmo() )
		bPossiblySwitch = true;

	if ( Pickup == None )
		bPossiblySwitch = true;

	for (m = 0; m < NUM_FIRE_MODES; m++)
    {
		if ( FireMode[m] != None )
			FireMode[m].Instigator = Instigator;
	}

	if ( ChaosWeaponPickup(Pickup) != None )
		MyCount = ChaosWeaponPickup(Pickup).MyCount;

	else
		MyCount = W.Count;

	WP = WeaponPickup(Pickup);

	A = Ammunition(Instigator.FindInventoryType(AmmoType[MyCount].AmmoClass));
	if ( A == None || A.Class != AmmoType[MyCount].AmmoClass && WP == None)
    {
        A = Spawn(AmmoType[MyCount].AmmoClass, Instigator);
		Instigator.AddInventory(A);
	}
	// We should either give ammo that was found in the gun if it was dropped
    if ( WP != None && WP.AmmoAmount[0] > 0 )
        A.AddAmmo(WP.AmmoAmount[0]);
	else
        A.AddAmmo(A.InitialAmount);

	A.GotoState('');

	if ( Instigator.Weapon != W )
		W.ClientWeaponSet(bPossiblySwitch);
	if ( !bJustSpawned )
		Destroy();
	SwitchFireMode(Count);
	OldCount=Count;
}


//----------------------------------------------------------------------
// BringUp
// needed to add this check for a multi-ammo weapon
//----------------------------------------------------------------------
simulated function BringUp(optional Weapon PrevWeapon)
{
	// Remove old Attchment and spawn new one with correct skin
	if (Instigator != None && Instigator.Weapon != None && instigator.Weapon == self)
    {
		AttachmentClass = AmmoType[Count].Attachment;
        if ( AttachmentClass != none)
			DetachFromPawn(instigator);
		AttachToPawn(Instigator);
	}
	Super.BringUp(PrevWeapon);
}


//----------------------------------------------------------------------
// SwitchFireMode. Makes the gun's fire modes change.
//----------------------------------------------------------------------
function SwitchFireMode(byte MyCount)
{

    if (Instigator == None)
      return;
    if (FireMode[0].IsA('ChaosWeaponProjectileFire') )
		if ( ammotype.length > 0 )
         {
        ChaosWeaponProjectileFire(FireMode[0]).ChangeMode(MyCount);
        FireMode[0].AmmoClass = AmmoType[MyCount].AmmoClass;
       AmmoClass[0] = AmmoType[MyCount].AmmoClass;
	Ammo[0] = Ammunition(Instigator.FindInventoryType(AmmoClass[0]));
	  }

	if (FireMode[1].IsA('ChaosWeaponProjectileFire') )
		if ( ammotype.length > 0 )
        {
        ChaosWeaponProjectileFire(FireMode[1]).ChangeMode(MyCount);
        FireMode[1].AmmoClass = AmmoType[MyCount].AmmoClass;
    AmmoClass[1] = AmmoType[MyCount].AmmoClass;
	Ammo[1] = Ammunition(Instigator.FindInventoryType(AmmoClass[1]));
	}
	// Remove old Attchment and spawn new one with correct skin
	if (instigator.Weapon == self)
    {
		AttachmentClass = AmmoType[MyCount].Attachment;
        if ( AttachmentClass != none)
			DetachFromPawn(instigator);
		AttachToPawn(Instigator);
	}
	SoundCount=MyCount;
    if ( ammotype.length > 0 )
    PickupClass=AmmoType[MyCount].Pickup;
	Count = MyCount;
}


//-------------------------------------------------------------------------------------------------
//SuperMaxOutAmmo
//-------------------------------------------------------------------------------------------------
simulated function SuperMaxOutAmmo()
{
	local byte m;
	local inventory Inv;
	for ( m = 0; m < AmmoType.length; m++) {
		Inv = Pawn(Owner).FindInventoryType(AmmoType[m].AmmoClass);
		if ( Inv != None ) {
			//Mutant fix for limiting spammy ammo types
			if (Level.Game.IsA('xMutantGame') && AmmoType[m].bSuperAmmoLimit)
				Ammunition(Inv).AmmoAmount = Ammunition(Inv).default.MaxAmmo;
			else
				Ammunition(Inv).AmmoAmount = 999;
		}
	}
}


//-------------------------------------------------------------------------------------------------
// NextWeapon
// This code handles the weapons swtiching better than Epics as it has more detialed checks
//-------------------------------------------------------------------------------------------------
simulated function Weapon NextWeapon(Weapon CurrentChoice, Weapon CurrentWeapon) {
	if ( HasAmmo() )
    {
		if ( (CurrentChoice == None) )
        {
			if ( CurrentWeapon != self )
			CurrentChoice = self;
		}
		else if (InventoryGroup == CurrentWeapon.InventoryGroup && InventoryGroup == CurrentChoice.InventoryGroup)
        {
			if (
				( GroupOffset < CurrentChoice.GroupOffset && CurrentChoice.GroupOffset < CurrentWeapon.GroupOffset ) ||
				( CurrentWeapon.GroupOffset < GroupOffset && GroupOffset < CurrentChoice.GroupOffset ) ||
				( CurrentChoice.GroupOffset < CurrentWeapon.GroupOffset && CurrentWeapon.GroupOffset < GroupOffset)
			)
				CurrentChoice = self;
		}
		else if
        (
			( CurrentWeapon.InventoryGroup == InventoryGroup && CurrentWeapon.GroupOffset < GroupOffset) ||
			( CurrentWeapon.InventoryGroup == CurrentChoice.InventoryGroup && CurrentChoice.GroupOffset < CurrentWeapon.GroupOffset) ||
			( CurrentChoice.InventoryGroup == InventoryGroup && GroupOffset < CurrentChoice.GroupOffset ) ||
			( InventoryGroup < CurrentChoice.InventoryGroup && CurrentChoice.InventoryGroup < CurrentWeapon.InventoryGroup ) ||
			( CurrentWeapon.InventoryGroup < InventoryGroup && InventoryGroup < CurrentChoice.InventoryGroup ) ||
			( CurrentChoice.InventoryGroup < CurrentWeapon.InventoryGroup && CurrentWeapon.InventoryGroup < InventoryGroup)
		)
			CurrentChoice = self;
	}
	if ( Inventory == None )
		return CurrentChoice;
	else
		return Inventory.NextWeapon(CurrentChoice,CurrentWeapon);
}


//-------------------------------------------------------------------------------------------------
// PrevWeapon
// This code handles the weapons swtiching better than Epics as it has more detialed checks
//-------------------------------------------------------------------------------------------------
simulated function Weapon PrevWeapon(Weapon CurrentChoice, Weapon CurrentWeapon)
{
	if ( HasAmmo() )
    {
		if ( (CurrentChoice == None) )
        {
			if ( CurrentWeapon != self )
			CurrentChoice = self;
		}
		else if (InventoryGroup == CurrentWeapon.InventoryGroup && InventoryGroup == CurrentChoice.InventoryGroup)
        {
			if (
				( GroupOffset > CurrentChoice.GroupOffset && CurrentChoice.GroupOffset > CurrentWeapon.GroupOffset ) ||
				( CurrentWeapon.GroupOffset > GroupOffset && GroupOffset > CurrentChoice.GroupOffset ) ||
				( CurrentChoice.GroupOffset > CurrentWeapon.GroupOffset && CurrentWeapon.GroupOffset > GroupOffset)
			)
				CurrentChoice = self;
		}
		else if
        (
			( CurrentWeapon.InventoryGroup == InventoryGroup && CurrentWeapon.GroupOffset > GroupOffset) ||
			( CurrentWeapon.InventoryGroup == CurrentChoice.InventoryGroup && CurrentChoice.GroupOffset > CurrentWeapon.GroupOffset) ||
			( CurrentChoice.InventoryGroup == InventoryGroup && GroupOffset > CurrentChoice.GroupOffset ) ||
			( InventoryGroup > CurrentChoice.InventoryGroup && CurrentChoice.InventoryGroup > CurrentWeapon.InventoryGroup ) ||
			( CurrentWeapon.InventoryGroup > InventoryGroup && InventoryGroup > CurrentChoice.InventoryGroup ) ||
			( CurrentChoice.InventoryGroup > CurrentWeapon.InventoryGroup && CurrentWeapon.InventoryGroup > InventoryGroup)
		)
			CurrentChoice = self;
	}
	if ( Inventory == None )
		return CurrentChoice;
	else
		return Inventory.PrevWeapon(CurrentChoice,CurrentWeapon);
}


// Special AI Interface for Chaos Multi-Ammo/Functional Weapons
//-------------------------------------------------------------------------------------------------
// BotPickSpecialAmmo
//	Gives this weapon to a player. Also adds extra ammo types.
//-------------------------------------------------------------------------------------------------
function BotPickSpecialAmmo(Bot B);


//-------------------------------------------------------------------------------------------------
// HasSpecificAmmo
// Used by the Bot AI when it wants a special ammo type
//-------------------------------------------------------------------------------------------------
function bool HasSpecificAmmo(byte MyCount)
{
	local Inventory Inv;

	if (Pawn(Owner) == none)
		return false;
	inv = Pawn(Owner).FindInventoryType(AmmoType[MyCount].AmmoClass);
			if (inv != none  && Ammunition(inv).HasAmmo())
			   return true;
	return false;
}
// End of Special AI Interface for Chaos Multi-Ammo/Functional Weapons

defaultproperties
{
     bNoAmmoInstances=False
     GroupOffset=64
}
